#include "jservice_runner.h"
#include "jservice_msg.h"
#include "jservice.h"
#include <Windows.h>
#include <assert.h>
using namespace std::tr1;

struct JServiceRunnerArgs {
	int index;
	JServiceRunner* runner;
};
DWORD JServiceRunner::DoWork( void* args )
{
	JServiceRunnerArgs* runnerArgs = (JServiceRunnerArgs*)args;
	JServiceRunner* runner = runnerArgs->runner;
	int index = runnerArgs->index;
	delete runnerArgs;
	for(;;) {
		EnterCriticalSection(&runner->m_criServices);
		JService* service = runner->dequeueService();
		if(!service) {
			runner->m_listSleepingThread.push_back(index);
			LeaveCriticalSection(&runner->m_criServices);
			WaitForSingleObject(runner->m_vecEvents[index], INFINITE);		
			continue;
		}
		LeaveCriticalSection(&runner->m_criServices);
		

		JServiceMsg* msg = service->dequeueMsg();
		if(msg == NULL) {
			printf("msg is empty\n");
			assert(0);
		}
		JService* srcService = runner->getServiceById(msg->sourceId);
		
		
		service->onMsg(srcService, msg->type, msg->session, msg->data);

		delete msg;
		EnterCriticalSection(&runner->m_criServices);
		service->m_listMsgs.pop_front();
		if(service->m_listMsgs.size() > 0) {			
			runner->m_listRunning.push_back(service);			
		}
		LeaveCriticalSection(&runner->m_criServices);
	}
}

void JServiceRunner::sendServiceMsg( int sourceId, int destId, int cmd, int sessionId, void* data )
{	
	JService* destService = this->getServiceById(destId);
	if(!destService) {
		return;
	}

	JServiceMsg* msg = new JServiceMsg;
	msg->sourceId = sourceId;
	msg->destId = destId;
	msg->data = data;
	msg->type = cmd;
	msg->session = sessionId;
	bool needToAdd = !destService->m_working;
	int indexToSet = -1;
	EnterCriticalSection(&m_criServices);
	if(msg == NULL) {
		assert(0);
	}
	destService->tryQueueMsg(msg);
	
	if(destService->m_listMsgs.size() == 1) {
		m_listRunning.push_back(destService);

		if(m_listSleepingThread.size()) {
			int index = *m_listSleepingThread.begin();
			m_listSleepingThread.pop_front();
			indexToSet = index;			
		}
	}	
	LeaveCriticalSection(&m_criServices);

	if(indexToSet >= 0) {
		SetEvent(m_vecEvents[indexToSet]);
	}
}

JService* JServiceRunner::getServiceById( int id )
{
	JService* ret = NULL;
	unordered_map<int, JService*>::iterator iter;
	iter = m_mapServices.find(id);
	if(iter != m_mapServices.end()) {
		ret = iter->second;
	}
	return ret;
}

JService* JServiceRunner::dequeueService()
{
	JService* ret = NULL;
	if(!m_listRunning.empty()) {
		ret = *m_listRunning.begin();
		m_listRunning.pop_front();
	}
	return ret;
}


int JServiceRunner::StartService2( JService* service, void* args )
{
	service->m_runner = this;
	EnterCriticalSection(&m_criServices);
	service->m_id = m_currentId ++;	
	m_mapServices[service->m_id] = service;
	service->onStart(args);
	LeaveCriticalSection(&m_criServices);
	
	return service->m_id;
}

JServiceRunner::JServiceRunner()
{
	m_currentId = 0;
	InitializeCriticalSection(&m_criServices);
	m_event = CreateEvent(NULL, false, false, NULL);
}

void JServiceRunner::run( int threads )
{
	m_running = 0;
	m_count = threads;
	for(int i = 0; i < threads; i++) {
		JServiceRunnerArgs* args = new JServiceRunnerArgs;
		args->index = i;
		args->runner = this;
		m_vecEvents.push_back(CreateEvent(NULL, FALSE, FALSE, NULL));
		m_vecThreads.push_back(CreateThread(NULL, 0, &JServiceRunner::DoWork, args, 0, 0));
	}
}


